package com.hujiang.basic.search.common.converter.resp;

import com.alibaba.fastjson.JSONObject;
import com.hujiang.basic.search.common.converter.Converter;
import com.hujiang.basic.search.common.utils.ElasticUtil;
import com.hujiang.basic.search.model.HJSearchHit;
import com.hujiang.basic.search.model.HJSearchRequest;
import com.hujiang.basic.search.model.HJSearchResponse;
import org.apache.commons.collections.MapUtils;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.highlight.HighlightField;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Component
public class SearchHitsConverter implements Converter<SearchResponse, HJSearchResponse> {


    @Override
    public HJSearchResponse convert(SearchResponse in) {
        if (in == null) {
            return null;
        }
        HJSearchResponse result = new HJSearchResponse();
        result.setTotalHits(in.getHits().getTotalHits());
        if (in.getHits().hits() != null) {
            in.getHits().forEach(hit -> {
                result.getHits().add(new HJSearchHit(hit.getId(), hit.getScore(),
                        getHitFields(hit), getHighlight(hit.getHighlightFields())));
            });
        }
        if (in.getAggregations() != null) {
            //result.setAggs(ElasticUtil.formatAggs2JsonObject(in.getAggregations().asMap()));
        }
        return result;
    }

    public HJSearchResponse convert(SearchResponse in, HJSearchRequest request) {
        if (in == null) {
            return null;
        }
        HJSearchResponse result = new HJSearchResponse();
        if(in.getShardFailures().length==0 && in.getFailedShards()==0){
            result.setStatus(0);
            result.setTotalHits(in.getHits().getTotalHits());
            if (in.getHits().hits() != null) {
                in.getHits().forEach(hit -> {
                    result.getHits().add(new HJSearchHit(hit.getId(), hit.getScore(),
                            getHitFields(hit), getHighlight(hit.getHighlightFields())));
                });
            }
            if (in.getAggregations() != null) {
                result.setAggs(ElasticUtil.formatAggs2JsonObject(in.getAggregations().asMap(), getStartFromAggs(request)));
            }
        }else {
            result.setStatus(-1);
            result.setMessage(in.getShardFailures()[0].getCause().getMessage());
        }
        return result;

    }


    private Map<String, List<String>> getHighlight(Map<String, HighlightField> highlightFields) {
        if (MapUtils.isNotEmpty(highlightFields)) {
            Map<String, List<String>> highlights = new HashMap<>();
            highlightFields.forEach((k, v) -> {
                List<String> fragments = new ArrayList<String>();
                for (Text text : v.getFragments()) {
                    fragments.add(text.toString());
                }
                highlights.put(k, fragments);
            });
            return highlights;
        }
        return null;
    }


    private Map<String, Object> getHitFields(SearchHit hit) {
        if (hit.getSource() == null) {
            HashMap<String, Object> fieldsData = new HashMap<String, Object>();
            if (MapUtils.isNotEmpty(hit.getFields())) {
                hit.getFields().values().forEach((field -> {
                    fieldsData.put(field.getName(), field.getValues().size() > 1 ? field.getValues() : field.getValue());
                }));
            }
            return fieldsData;
        }
        return hit.getSource();
    }

    public int getStartFromAggs(HJSearchRequest in) {
        if (in.getAggs() != null) {
            for (Map.Entry<String, Object> entry : in.getAggs().entrySet()) {
                if (entry != null && entry.getValue() instanceof JSONObject) {
                    JSONObject termJson = (JSONObject) (((JSONObject) entry.getValue()).get("terms"));
                    if (termJson != null && termJson.containsKey("from")) {
                        return termJson.getIntValue("from");
                    }
                }
            }
        }

        return 0;
    }
}
